<?php
/**
 * A database connection class.
 *
 * @author Mark Dohmen.
 */
final class Database {
	
	/**
	 * Instance of this class.
	 */
	private static $database = NULL;
	
	/**
	 * Instance of PHPs PDO.
	 */
	private $db = NULL;
	
	/**
	 * Remember the last results.
	 */
	private $statement = NULL;
	
	/**
	 * Connects to the database.
	 */
	final public function connect(string $database = NULL) {
		if (($this->db instanceof Database) && $database === NULL) {
			return;
		}
		$this->db = NULL;
		try {
			$this->db = new PDO(
				"mysql:host=" . Constants::DB_HOST . ";dbname=" . $database, 
				Constants::DB_USER, 
				Constants::DB_PASS
			);
		} catch (PDOException $e) {
			throw new Exception("Error connecting to the Database!");
		}
	}
	
	/**
	 * Checks if we are connected to a database or not.
	 *
	 * @return true/false
	 */
	final public function isConnected() {
		if ($this->db instanceof PDO) {
			return (boolean) true;
		}
		return (boolean) false;
	}
	
	/**
	 * Executes a query.
	 *
	 * @param $query
	 */
	final public function query(string $query) {
		if (!$this->isConnected()) {
			$this->connect();
		}
		$query = DatabaseUtils::filter($query);
		try {
			$this->db->beginTransaction();
			if (strstr($query, "SELECT")) {
				$this->statement = $this->db->query($query);
			} else {
				$this->db->exec($query);	
			}
			$this->db->commit();
		} catch(PDOException $e) {
			$this->db->rollBack();
		}
	}
	
	/**
	 * Returns an array with the results.
	 *
	 * @param $query
	 * @return $result
	 */
	final public function fetchArray(string $query = NULL) {
		if ($query != NULL) {
			$this->query($query);
		}
		return (array) $this->statement->fetchAll();
	}
	
	/**
	 * Returns an object with the results.
	 *
	 * @param $query
	 * @return $data
	 */
	final public function fetchObject(string $query = NULL) {
		if ($query != NULL) {
			$this->query($query);
		}
		foreach($this->statement->fetchAll() as $key => $value) {
			$data->$key[] = $value;
		}
		return (object) $data;
	}
	
	/**
	 * Gets the last insert ID
	 *
	 * @return $id
	 */
	final public function lastInsertID() {
		return (int) $this->db->lastInsertId();	
	}
	
	/**
	 * Return the number of rows.
	 * We can specify a new query to be used,
	 * Or we recycle the previews results if they are good enough
	 *
	 * @param $query
	 * @return $count
	 */
	final public function numRows(string $query = NULL) {
		if ($query != NULL) {
			$this->query($query);
		}
		return (int) count($this->statement->fetchAll());
	}
	
	/**
	 * Returns an instance of this class.
	 *
	 * @return $database
	 */
	final public static function getDatabase() {
		if (!(self::$database instanceof Database)) {
			self::$database = new Database();
		}
		return (object) self::$database;
	}
}
?>